pseudoPODs
Smart Class Members That Masquerade as POD Members
If you convert an existing POD member to a pseudoPOD member, most of the code using the existing member will not need changing. However, no masquerade is perfect, and I have found several cases that require changing the code.
1) printf(...) Prodding:
Variadic functions such as printf(...) statements need some compiler helper, i.e. if the pseudoPOD is an argument in a call that can have a variable number of arguments, the compiler needs to be told the type of the member. The statement:
printf ("value of smart member fred.int1 = %d", (int)fred.int1);
compiles and runs correctly, but remove "(int)" and the compiler produces the error message:
"cannot pass objects of non-POD type 'class fred2_c::int3_nest' through '...'; call will abort at runtime".
C++ I/O streams (e.g.cout << fred.int1; ) don't have this problem.
2) Template Prodding:
Templates sometimes require similar prodding. For example, the absolute value template used in file main.cpp accompanying this article (www.dlmowery.com/pseudoPOD/main.cpp):
template <class T> T absfloat(T a) {
if (a<0) {return -a;} else {return a;}
}
attempts to make a copy of argument a, which I've intentionally made impossible for pseudoPODs, so
absfloat( fred.int3 );
will fail if fred.int3 is a pseudoPOD, but work correctly if we use a typecast to prod the compiler into converting the pseudoPOD to a POD, as in
absfloat( (int)fred.int3 );
Some template calls require prodding, and others don't. For example,
absfloat( fred.int3 - 48 );
does not require changing the code, because the -48 part already persuades the compiler to convert fred.int3 to an integer.
The macro equivalent,
#define absfloat_macro(a) ((a)<0)?-(a):(a);
needs no recoding.
The compiler does not plainly say that it tried to make a copy of the pseudoPOD and was stymied, instead it complains that the copy constructor() or destructor() is private, so it can't use it, e.g.
"'fred2_c::int3_nest::~int3_nest()' is private"
So the keyword "private" is often your cue to prod the compiler by adding a type cast.
3) Passing pseudoPOD by Reference:
If you pass a member to a function by reference (rather than by value, which is more common), then using a POD for the argument will succeed, but using a pseudoPOD will fail. You can often correct the problem, without changing all the places where the function is called, by converting the function to a template, e.g. change function addbyadr() from:
int addbyadr (int &a, int b) { a = a + b; return (a); }
to:
template <class T> int addbyadr (T &a,int b) {a = a + b; return(a);}
and now argument &a can handle both PODs and pseudoPODs. The template does not require type cast prodding because passing by reference does not make a copy.
4) Pointer Variable Type:
If you use pointer variables to point at pseudoPODs you'll have to change the type of the pointer, for example, if a class fred_c contained a pseudoPOD member int1, then you'd have to change
int *int1p; to fred_c::int3_c *int1p;